#include "tcp_connection.hh"

#include <iostream>

using namespace std;

void debug(TCPSegment seg) {
    cout << "---------------------" << endl;
    cout << seg.header().to_string() << endl;
    cout << "syn = " << seg.header().syn << endl;
    cout << "ack = " << seg.header().ack << endl;
    cout << "fin = " << seg.header().fin << endl;
    cout << "rst = " << seg.header().rst << endl;
    cout << "seqno = " << seg.header().seqno << endl;
    cout << "ackno = " << seg.header().ackno << endl;
    cout << "winsize = " << seg.header().win << endl;
    cout << "---------------------" << endl;
}

size_t TCPConnection::remaining_outbound_capacity() const { 
    return _sender.stream_in().remaining_capacity();
}

size_t TCPConnection::bytes_in_flight() const { 
    return _sender.bytes_in_flight();
}

size_t TCPConnection::unassembled_bytes() const { 
    return _receiver.unassembled_bytes();
}

size_t TCPConnection::time_since_last_segment_received() const { 
    return _cur_time - _last_segment_received_time;
}

bool TCPConnection::can_close() {
    // 发送方处于FIN_ACKED状态，接收方处于FIN_RECV状态
    return _receiver.stream_out().input_ended() && _sender.stream_in().eof() && _sender.bytes_in_flight() == 0 && _sender.next_seqno_absolute() == _sender.stream_in().bytes_written() + 2;
}

void TCPConnection::segment_received(const TCPSegment &seg) {
    if (!_active)
        return; 
    // 设置了RST，同时将inbound和outbound设置为error
    if (seg.header().rst) {
        close_conn();
        return;
    }
    if (seg.header().syn)
        _syn = true;
    _last_segment_received_time = _cur_time;
    // 将报文传递给TCPReceiver
    _receiver.segment_received(seg);
    // 如果设置了ack,传递给发送端
    if (seg.header().ack) 
        _sender.ack_received(seg.header().ackno, seg.header().win);
    
    // 给保活报文回复
    if (_receiver.ackno().has_value() and (seg.length_in_sequence_space() == 0)
            and seg.header().seqno == _receiver.ackno().value() - 1) {
        _sender.send_empty_segment();
        add_field();
    }
    // 如果到来的报文段包含有seqno,则必须回复它ack报文
    if (seg.length_in_sequence_space() > 0) {
        _sender.fill_window();
        if (_sender.segments_out().empty())
            _sender.send_empty_segment();
        add_field();
    }
    if (_receiver.stream_out().input_ended() && !_sender.stream_in().eof())
        _linger_after_streams_finish = false;
    if (!_linger_after_streams_finish && can_close()) {
        _active = false;
    }
}

bool TCPConnection::active() const { 
    return _active;    
}

void TCPConnection::close_conn() {
    _sender.stream_in().set_error();
    _receiver.stream_out().set_error();
    _active = false;
}

size_t TCPConnection::write(const string &data) {
    if (!_active)
        return 0;
    size_t ret = _sender.stream_in().write(data);
    _sender.fill_window();
    add_field();
    return ret;
}

//! \param[in] ms_since_last_tick number of milliseconds since the last call to this method
void TCPConnection::tick(const size_t ms_since_last_tick) { 
    if (!_active)
        return;    
    _cur_time += ms_since_last_tick;
    _sender.tick(ms_since_last_tick);
    if (_syn) {
        _sender.fill_window();
        add_field();
    }
    if (_sender.consecutive_retransmissions() > TCPConfig::MAX_RETX_ATTEMPTS) {
        send_rst();
        close_conn();
        return;
    }
    if (_linger_after_streams_finish) {
        if (can_close() && _cur_time >= _last_segment_received_time + 10 * _cfg.rt_timeout) {
            _active = false;
        }
    } 
}

void TCPConnection::end_input_stream() {
    _sender.stream_in().end_input();
    _sender.fill_window();
    add_field();
}

void TCPConnection::connect() {
    if (_syn || !_active)
        return;
    // 发送SYN
    _syn = true;
    _sender.fill_window();
    add_field();
}

void TCPConnection::add_field() {
    while (!_sender.segments_out().empty()) {
        TCPSegment seg = _sender.segments_out().front();
        _sender.segments_out().pop();
        if (_receiver.ackno().has_value()) {
            seg.header().ackno = _receiver.ackno().value();
            seg.header().ack = true;
        }
        size_t win_max = std::numeric_limits<uint16_t>::max();
        seg.header().win = std::min(win_max, _receiver.window_size());
        _segments_out.push(seg);
    }
}

void TCPConnection::send_rst() {
    TCPSegment seg;
    seg.header().rst = true;
    seg.header().seqno = _sender.next_seqno();
    _segments_out.push(seg);
}

TCPConnection::~TCPConnection() {
    try {
        if (active()) {
            send_rst();
            close_conn();
        }
    } catch (const exception &e) {
        std::cerr << "Exception destructing TCP FSM: " << e.what() << std::endl;
    }
}
